package com.lizardmind.haofudoctor.manager

import android.app.ProgressDialog
import android.content.Context
import android.widget.Toast
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.linxiao.framework.BaseApplication
import com.linxiao.framework.net.*
import com.linxiao.framework.net.interceptor.CacheInterceptor
import com.lizardmind.haofudoctor.other.EncryptInterceptor
import com.linxiao.framework.util.ke
import com.lizardmind.haofudoctor.other.HeadInfoInterceptor
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.Disposable
import io.reactivex.functions.Action
import io.reactivex.functions.Consumer
import io.reactivex.schedulers.Schedulers
import kotlinx.coroutines.experimental.channels.produce
import retrofit2.HttpException
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.scalars.ScalarsConverterFactory
import java.io.IOException

/**
 * 网络请求的一些封装
 * Created by Extends on 2017/10/19 10:19
 */
class NetManager {
    fun getNetManager():BaseAPI{
        //TODO:正式项目可以删掉infoCatchInterceptor
        // 这些配置可以放在App工程的网络模块中，这里简要处理就不写了
        val infoCatchInterceptor = HttpInfoCatchInterceptor()
        infoCatchInterceptor.setCatchEnabled(true)
        infoCatchInterceptor.setHttpInfoCatchListener { entity ->
            entity.logOut()
            //do something......
        }
        return RetrofitManager.createRetrofitBuilder(baseUrl)
                .addConvertFactory(ScalarsConverterFactory.create())
                .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
                .addCustomInterceptor(HeadInfoInterceptor())
                .addCustomInterceptor(CacheInterceptor())
                .addCustomInterceptor(EncryptInterceptor())
                .addCustomInterceptor(infoCatchInterceptor)
                .build(BaseAPI::class.java)
    }

    /**
     * 顶级方法
     * @param map 键值对参数
     * @param onNext Observer的onNext方法
     * @param onComplete Observer的onComplete方法
     * @param time 数据缓存时间，0表示不缓存，1表示缓存1s
     */
    inline fun <reified T> getPk(map:Map<String,String>, onNext:Consumer<T>,
                                   onComplete:Action= Action {  }, time:Int=0):Disposable{
        val token = object: TypeToken<T>(){}.type
        return NetManager.baseAPI.postApi(map,time)
                .subscribeOn(Schedulers.io())
                .retry(3)
                .doOnNext { ke(map.toString(),it) }
                .map { Gson().fromJson<T>(it,token) }
                .observeOn(AndroidSchedulers.mainThread())
                .unsubscribeOn(Schedulers.io())
                .subscribe(onNext, Consumer {
                    Toast.makeText(BaseApplication.getAppContext(),
                            when(it){
                                is HttpException->"服务暂不可用"
                                is IOException->"连接服务器失败"
                                else->it.message
                            }, Toast.LENGTH_SHORT).show()
                    //当出错了后回掉onComplete方法，主要是执行onComplete里可能有的如Dialog.dismiss()方法
                    onComplete.run()
                },onComplete)
    }

    companion object {
        val baseUrl = "http://doctor.lizardmind.com/"
        val baseAPI : BaseAPI by lazy { NetManager().getNetManager() }


        @Deprecated("过时的方法，不要使用！！！")
        fun postApi(map:Map<String,String>, onNext:(v:String)->Unit={}, onComplete:()->Unit={}, time:Int=0):Disposable{
            return baseAPI.postApi(map,time)
                    .subscribeOn(Schedulers.io())
                    .retry(3)
                    .doOnNext {
                        ke(map.toString(),it)
                    }
                    .observeOn(AndroidSchedulers.mainThread())
                    .unsubscribeOn(Schedulers.io())
                    .subscribe({onNext(it)}, {
                        Toast.makeText(BaseApplication.getAppContext(),
                                when(it){
                                    is HttpException->"服务暂不可用"
                                    is IOException->"连接服务器失败"
                                    else->it.message
                                }, Toast.LENGTH_SHORT).show()
                    }, { onComplete() })
        }
    }
}

/**
 * 顶级方法
 * @param map 键值对参数
 * @param onNext Observer的onNext方法
 * @param onComplete Observer的onComplete方法
 * @param time 数据缓存时间，0表示不缓存，1表示缓存1s
 * @param context 如果需要公用的加载框，就传入activity的context，Application的不行
 */
inline fun <reified T> postApi(map:Map<String,String>, onNext:Consumer<T>,
                               onComplete:Action= Action {  }, time:Int=0,context:Context?=null):Disposable{
    val token = object: TypeToken<T>(){}.type
    val progressDialog = if(context!=null) ProgressDialog(context) else null
    progressDialog?.show()
    return NetManager.baseAPI.postApi(map,time)
            .subscribeOn(Schedulers.io())
            .retry(3)
            .doOnNext { ke(it,map.toString());}
            .map { Gson().fromJson<T>(it,token) }
            .observeOn(AndroidSchedulers.mainThread())
            .unsubscribeOn(Schedulers.io())
            .subscribe(onNext, Consumer {
                Toast.makeText(BaseApplication.getAppContext(),
                        when(it){
                            is HttpException->"服务暂不可用"
                            is IOException->"连接服务器失败"
                            else->it.message
                        }, Toast.LENGTH_SHORT).show()
                //当出错了后回掉onComplete方法，主要是执行onComplete里可能有的如Dialog.dismiss()方法
                if(progressDialog?.isShowing == true){
                    progressDialog.dismiss()
                }
                onComplete.run()
            }, Action {
                if(progressDialog?.isShowing == true){
                    progressDialog.dismiss()
                }
                onComplete.run()
            })
}